//---------------------------------------------------------------------
// Original Author: TonyDeSweet
//
// Description: Helper class for PInvoke Win32API.
//
// Creation Date: Feb 21, 2006
//---------------------------------------------------------------------
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

using Microsoft.Win32.SafeHandles;

using ComTypes = System.Runtime.InteropServices.ComTypes;

// I don't care if there are some values that aren't used yet in this interop class.
#pragma warning disable 0414

namespace Pscx.Interop
{
    static class Dll
    {
        public const string Advapi32 = "advapi32.dll";
        public const string Kernel32 = "kernel32.dll";
        public const string User32 = "user32.dll";

    }

    static class NativeMethods
    {
        #region Constants
        public const int FALSE = 0;
        public const int TRUE = 1;

        public const int SUCCESS = 0x0;
        public const int ERROR_SUCCESS = 0x0;
        public const int ERROR_ACCESS_DENIED = 0x5;
        public const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
        public const int ERROR_BAD_LENGTH = 0x18;
        public const int ERROR_INSUFFICIENT_BUFFER = 0x7a;
        public const int ERROR_NONE_MAPPED = 0x534;
        public const int ERROR_NO_TOKEN = 0x3f0;
        public const int ERROR_NOT_ALL_ASSIGNED = 0x514;
        public const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
        public const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;

        public const int SYMLINK_FLAG_DIRECTORY = 1;

        public const int MAX_PATH = 260;
        #endregion

        #region advapi32

        [DllImport(Dll.Advapi32, EntryPoint = "LookupPrivilegeValueW", CharSet = CharSet.Auto, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool LookupPrivilegeValue(
            string lpSystemName,
            string lpName,
            ref LUID Luid);

        [DllImport(Dll.Advapi32, CharSet = CharSet.Auto, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool LookupPrivilegeName(
            string lpSystemName,
            ref LUID lpLuid,
            StringBuilder lpName,
            ref int cbName);

        [DllImport(Dll.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool OpenProcessToken(
            IntPtr hProcess,
            TokenAccessLevels DesiredAccess,
            ref SafeTokenHandle TokenHandle);

        [DllImport(Dll.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool OpenThreadToken(
            IntPtr ThreadToken,
            TokenAccessLevels DesiredAccess,
            bool OpenAsSelf,
            ref SafeTokenHandle TokenHandle);

        [DllImport(Dll.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool LogonUser(
          string principal,
          string authority,
          string password,
          LogonTypes logonType,
          LogonProviders logonProvider,
          ref SafeTokenHandle token);

        #endregion

        #region advapi32!AdjustTokenPrivileges
        [DllImport(Dll.Advapi32, SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool AdjustTokenPrivileges(
            SafeTokenHandle TokenHandle,
            bool DisableAllPrivileges,
            byte[] NewState,
            int BufferLength,
            IntPtr PreviousState,
            IntPtr ReturnLength);

        #endregion

        #region user32

        [DllImport(Dll.User32)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern IntPtr GetOpenClipboardWindow();

        [DllImport(Dll.User32, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        #endregion

        #region kernel32

        [DllImport(Dll.Kernel32, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport(Dll.Kernel32, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetShortPathName(
           [MarshalAs(UnmanagedType.LPTStr)] string lpszLongPath,
           [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszShortPath,
           uint cchBuffer);


        [DllImport(Dll.Kernel32, SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool CreateHardLink(
            string lpszHardLinkPath,
            string lpszExistingFileName,
            IntPtr lpSecurityAttributes);

        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);

        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool DeleteFile(string lpFileName);

        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern bool RemoveDirectory(string lpPathName);

        #endregion

        #region kernel32!CreateFile

        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        public static extern SafeFileHandle CreateFile(
            string lpFileName,
            FileAccess dwDesiredAccess,
            FileShare dwShareMode,
            IntPtr lpSecurityAttributes,
            CreationDisposition dwCreationDisposition,
            FileAttributes dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        [Flags]
        public enum FileAccess : uint
        {
            GenericRead = 0x80000000,
            GenericWrite = 0x40000000,
            GenericExecute = 0x20000000,
            GenericAll = 0x10000000,
        }

        [Flags]
        public enum FileShare : uint
        {
            None = 0x00000000,
            Read = 0x00000001,
            Write = 0x00000002,
            Delete = 0x00000004,
        }

        public enum CreationDisposition : uint
        {
            New = 1,
            CreateAlways = 2,
            OpenExisting = 3,
            OpenAlways = 4,
            TruncateExisting = 5,
        }

        [Flags]
        public enum FileAttributes : uint
        {
            Readonly = 0x00000001,
            Hidden = 0x00000002,
            System = 0x00000004,
            Directory = 0x00000010,
            Archive = 0x00000020,
            Device = 0x00000040,
            Normal = 0x00000080,
            Temporary = 0x00000100,
            SparseFile = 0x00000200,
            ReparsePoint = 0x00000400,
            Compressed = 0x00000800,
            Offline = 0x00001000,
            NotContentIndexed = 0x00002000,
            Encrypted = 0x00004000,
            Write_Through = 0x80000000,
            Overlapped = 0x40000000,
            NoBuffering = 0x20000000,
            RandomAccess = 0x10000000,
            SequentialScan = 0x08000000,
            DeleteOnClose = 0x04000000,
            BackupSemantics = 0x02000000,
            PosixSemantics = 0x01000000,
            OpenReparsePoint = 0x00200000,
            OpenNoRecall = 0x00100000,
            FirstPipeInstance = 0x00080000
        }
        #endregion

        #region kernel32!FindFirstVolumeMountPoint
        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern SafeFindVolumeMountPointHandle FindFirstVolumeMountPoint(
            string lpszRootPathName,
            StringBuilder lpszVolumeMountPointName,
            int cchStringBufferLength);
        #endregion

        #region kernel32!FindNextVolumeMountPoint
        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool FindNextVolumeMountPoint(
            SafeFindVolumeMountPointHandle hFindVolume,
            StringBuilder lpszVolumeMountPointName,
            int cchStringBufferLength);
        #endregion

        #region kernel32!FindVolumeMountPointClose
        [DllImport(Dll.Kernel32, SetLastError = true)]
        public static extern bool FindVolumeMountPointClose(IntPtr hFindVolumeMountPoint);
        #endregion

        #region kernel32!GetVolumeNameForVolumeMountPoint
        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool GetVolumeNameForVolumeMountPoint(
            string lpszVolumeMountPoint,
            StringBuilder lpszVolumeName,
            int cchStringBufferLength);

        #endregion

        #region kernel32!DeleteVolumeMountPoint
        [DllImport(Dll.Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool DeleteVolumeMountPoint(string lpwszVolumeMountPoint);
        #endregion
    }

    #region Enumerations
    public enum ReparsePointType : uint
    {
        MountPoint = 0xA0000003,
        SymbolicLink = 0xA000000C,
        HierarchicalStorage = 0xC0000004,
        SingleInstanceStore = 0x80000007,
        DistributedFileSystem = 0x8000000A,
        FilterManager = 0x8000000B,
    }


    [Flags]
    enum TokenAccessLevels
    {
        AssignPrimary = 0x00000001,
        Duplicate = 0x00000002,
        Impersonate = 0x00000004,
        Query = 0x00000008,
        QuerySource = 0x00000010,
        AdjustPrivileges = 0x00000020,
        AdjustGroups = 0x00000040,
        AdjustDefault = 0x00000080,
        AdjustSessionId = 0x00000100,

        Read = 0x00020000 | Query,

        Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,

        AllAccess = 0x000F0000 |
            AssignPrimary |
            Duplicate |
            Impersonate |
            Query |
            QuerySource |
            AdjustPrivileges |
            AdjustGroups |
            AdjustDefault |
            AdjustSessionId,

        MaximumAllowed = 0x02000000
    }

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin
    }

    enum LogonTypes : uint
    {
        Interactive = 2,
        Network,
        Batch,
        Service,
        NetworkCleartext = 8,
        NewCredentials
    }

    enum LogonProviders : uint
    {
        Default = 0, // default for platform (use this!)
        WinNT35,     // sends smoke signals to authority
        WinNT40,     // uses NTLM
        WinNT50      // negotiates Kerb or NTLM
    }

    [Flags]
    public enum PrivilegeStatus : uint
    {
        Disabled = 0,
        EnabledByDefault = 0x00000001,
        Enabled = 0x00000002,
        UsedForAccess = 0x80000000

    }
    #endregion

    #region Structures
    [StructLayout(LayoutKind.Sequential)]
    struct LUID
    {
        public uint LowPart;
        public uint HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct LUID_AND_ATTRIBUTES
    {
        public LUID Luid;
        public PrivilegeStatus Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct TOKEN_PRIVILEGES
    {
        public int PrivilegeCount;
        public LUID_AND_ATTRIBUTES Privileges;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct WIN32_FIND_DATA
    {
        public uint dwFileAttributes;
        public ComTypes.FILETIME ftCreationTime;
        public ComTypes.FILETIME ftLastAccessTime;
        public ComTypes.FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public uint dwReserved0;
        public uint dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
        public string cAlternateFileName;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    struct REPARSE_GUID_DATA_BUFFER
    {
        public ReparsePointType ReparseTag;
        public ushort ReparseDataLength;
        public ushort Reserved;

        public Guid ReparseGuid;
        public byte DataBuffer;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
    struct MOUNTPOINT_REPARSE_DATA_BUFFER
    {
        public ReparsePointType ReparseTag;
        public ushort ReparseDataLength;
        public ushort Reserved;

        // IO_REPARSE_TAG_MOUNT_POINT specifics follow
        public ushort SubstituteNameOffset;
        public ushort SubstituteNameLength;
        public ushort PrintNameOffset;
        public ushort PrintNameLength;

        public char PathBuffer;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
    struct SET_MOUNTPOINT_REPARSE_DATA_BUFFER
    {
        public uint ReparseTag;
        public uint ReparseDataLength;
        public ushort Reserved;
        public ushort ReparseTargetLength;
        public ushort ReparseTargetMaximumLength;
        public ushort Reserved1;
        public char ReparseTarget;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
    struct SYMLINK_REPARSE_DATA_BUFFER
    {
        public ReparsePointType ReparseTag;
        public ushort ReparseDataLength;
        public ushort Reserved;

        // IO_REPARSE_TAG_MOUNT_POINT specifics follow
        public ushort SubstituteNameOffset;
        public ushort SubstituteNameLength;
        public ushort PrintNameOffset;
        public ushort PrintNameLength;

        public uint Reserved1;

        public char PathBuffer;
    }


    #endregion

    #region SafeHandles

    class SafeFindVolumeMountPointHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        public SafeFindVolumeMountPointHandle() : base(true) { }
        protected override bool ReleaseHandle()
        {
            return NativeMethods.FindVolumeMountPointClose(handle);
        }
    }


    #endregion
}
